//------------------------------------------------------------------------------
// MemUtils.h
//------------------------------------------------------------------------------
// File provided for Microsoft Shared Source.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE.
//------------------------------------------------------------------------------
//
// Smart pointers and other memory helpers
//
//------------------------------------------------------------------------------

#pragma once

template<typename T, class Allocator = CCRTAllocator>
class CMemPtr :
    public CHeapPtr<T, Allocator>
{
public:
    HRESULT Allocate(size_t nElements = 1) throw()
    {
        return CHeapPtr<T, Allocator>::Allocate(nElements) ? S_OK : E_OUTOFMEMORY;
    }

    HRESULT AllocateBytes(size_t nBytes) throw()
    {
        return CHeapPtr<T, Allocator>::AllocateBytes(nBytes) ? S_OK : E_OUTOFMEMORY;
    }

    HRESULT Reallocate(size_t nElements = 1) throw()
    {
        return CHeapPtr<T, Allocator>::Reallocate(nElements) ? S_OK : E_OUTOFMEMORY;
    }

    HRESULT ReallocateBytes(size_t nBytes = 1) throw()
    {
        return CHeapPtr<T, Allocator>::ReallocateBytes(nBytes) ? S_OK : E_OUTOFMEMORY;
    }
};

// uses COM Heap API (CoTaskMemAlloc)
template <typename T>
class CComMemPtr : public CMemPtr<T, CComAllocator>
{
};

// uses LocalXXX Heap API
template <typename T>
class CLocalMemPtr : public CMemPtr<T, CLocalAllocator>
{
};

// uses GlobalXXX heap API
template <typename T>
class CGlobalMemPtr : public CMemPtr<T, CGlobalAllocator>
{
};

inline HRESULT CoAllocStringLen(PCWSTR pszSource, size_t cch, __deref_out_ecount_opt(cch+1) STRSAFE_LPWSTR *ppsz)
{
	HRESULT hr = E_POINTER;

	if (ppsz != NULL)
	{
		size_t cchTotal;

		*ppsz = NULL;
		hr = SizeTAdd(cch, 1, &cchTotal);

		if (SUCCEEDED(hr))
		{
			CComMemPtr<WCHAR> spsz;
			hr = spsz.Allocate(cchTotal);

			if (SUCCEEDED(hr))
			{
				hr = ::StringCchCopyNW(spsz, cchTotal, pszSource, cch);
				
				if (SUCCEEDED(hr))
				{
					*ppsz = spsz.Detach();
				}
			}
		}
	}

	return hr;
}

template <class T>
HRESULT CoCreate(CComPtrBase<T> & Result)
{
	HRESULT hr;
    CComObject<T> * Object;
    
	if (SUCCEEDED(hr = CComObject<T>::CreateInstance(&Object)))
    {
        Object->AddRef();
        Result.Attach(Object);
    }

    return hr; 
}
